package com.atstudent.gmall.search.biz.impl;
import cn.hutool.core.util.PageUtil;
import com.atstudent.gmall.search.entity.SearchAttr;
import com.atstudent.gmall.search.vo.SearchOrderMapVo;
import com.atstudent.gmall.search.vo.SearchRespAttrVo;
import com.atstudent.gmall.search.vo.SearchTmVo;
import com.google.common.collect.Lists;

import com.atstudent.gmall.search.biz.GoodsBizService;
import com.atstudent.gmall.search.dto.SearchParamDTO;
import com.atstudent.gmall.search.entity.Goods;
import com.atstudent.gmall.search.repository.GoodsRepository;
import com.atstudent.gmall.search.vo.SearchResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @Author 薛有朋
 * @CreatDate 2025/3/13 21:36
 **/
@Service
@Slf4j
public class GoodsBizServiceImpl implements GoodsBizService {

    //品牌聚合的参数
    private final String TMIDAGG = "tmIdAgg";
    private final String TMID = "tmId";
    private final String TMNAMEAGG = "tmNameAgg";
    private final String TMNAME = "tmName";
    private final String TMLOGOURLAGG = "tmLogoUrlAgg";
    private final String TMLOGOURL = "tmLogoUrl";

    //平台属性聚合参数
    private final String ATTRAGG = "attrAgg";
    private final String ATTRS = "attrs";
    private final String ATTRIDAGG = "attrIdAgg";
    private final String ATTRID = "attrs.attrId";
    private final String ATTRNAMEAGG = "attrNameAgg";
    private final String ATTRNAME = "attrs.attrName";
    private final String ATTRVALUEAGG = "attrValueAgg";
    private final String ATTRVALUE = "attrs.attrValue";

    //高亮的字段
    private final String TITLE = "title";

    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public void saveGoods(Goods goods) {
        goodsRepository.save(goods);
    }

    @Override
    public void deleteGoods(Long skuId) {
        goodsRepository.deleteById(skuId);
    }

    @Override
    public SearchResponseVo search(SearchParamDTO searchParamDTO) {

        log.info("GoodsBizServiceImpl...search...方法执行了...");

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        //构建分类的搜索条件
        Long category1Id = searchParamDTO.getCategory1Id();
        if (category1Id != null){
            boolQueryBuilder.must(QueryBuilders.termQuery("category1Id" ,category1Id ));
        }

        Long category2Id = searchParamDTO.getCategory2Id();
        if (category2Id != null){
            boolQueryBuilder.must(QueryBuilders.termQuery("category2Id" ,category2Id ));
        }

        Long category3Id = searchParamDTO.getCategory3Id();
        if (category3Id != null){
            boolQueryBuilder.must(QueryBuilders.termQuery("category3Id" ,category3Id ));
        }

        // 关键字的搜索条件
        String keyword = searchParamDTO.getKeyword();
        if (!StringUtils.isEmpty(keyword)){
            boolQueryBuilder.must(QueryBuilders.matchQuery("title" , keyword));
        }

        // 构建品牌的搜索条件
        String trademark = searchParamDTO.getTrademark();
        if (!StringUtils.isEmpty(trademark)){   //1:小米
            String[] split = trademark.split(":");
            String tmId = split[0];
            boolQueryBuilder.must(QueryBuilders.termQuery("tmId" , tmId));
        }

        // 构建平台属性的搜索条件
        String[] props = searchParamDTO.getProps();
        if (props != null && props.length > 0){
            for (String prop : props) {  // 8023:冰川蓝:颜色   ----> 平台属性的Id:平台属性的值:平台属性名称
                String[] propAttr = prop.split(":");
                long attrId = Long.parseLong(propAttr[0]);
                String attrValueName = propAttr[1];
                BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
                queryBuilder.must(QueryBuilders.termQuery("attrs.attrId" , attrId));
                queryBuilder.must(QueryBuilders.termQuery("attrs.attrValue" , attrValueName));
                NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery("attrs", queryBuilder , ScoreMode.None);
                boolQueryBuilder.must(nestedQuery);
            }
        }

        //  设置高亮的参数
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field(TITLE);
        highlightBuilder.preTags("<font color='red'>");
        highlightBuilder.postTags("</font>");

        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withHighlightBuilder(highlightBuilder)
                .build();

        // 构建排序搜索条件
        String order = searchParamDTO.getOrder();
        if (!StringUtils.isEmpty(order) && !"null".equals(order)){
            Sort sort = null;
            //1:dsc    2:dsc  1代表按热度分排序  2代表按价格排序
            String[] orderAttr = order.split(":");
            String field = orderAttr[0];
            String direction = orderAttr[1];
            switch (field){
                case "1" :
                    sort = Sort.by("asc".equalsIgnoreCase(direction) ? Sort.Direction.ASC : Sort.Direction.DESC , "hotScore");
                    break;
                case "2" :
                    sort = Sort.by("desc".equalsIgnoreCase(direction) ? Sort.Direction.DESC : Sort.Direction.ASC , "price");
                    break;
            }
            nativeSearchQuery.addSort(sort);
        }

        // 设置分页参数
        Integer pageNo = searchParamDTO.getPageNo(); //从第几页开始
        Integer pageSize = searchParamDTO.getPageSize();   //每页多少条数据
        nativeSearchQuery.setPageable(PageRequest.of(pageNo - 1 , pageSize));

        //设置品牌聚合的参数
        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms(TMIDAGG).field(TMID).size(100);
        termsAggregationBuilder.subAggregation(AggregationBuilders.terms(TMNAMEAGG).field(TMNAME).size(10));
        termsAggregationBuilder.subAggregation(AggregationBuilders.terms(TMLOGOURLAGG).field(TMLOGOURL).size(10));
        nativeSearchQuery.addAggregation(termsAggregationBuilder);

        // 设置平台属性聚合参数
        NestedAggregationBuilder attrsAggregationBuilder = AggregationBuilders.nested(ATTRAGG, ATTRS);
        TermsAggregationBuilder attrIdAggregationBuilder = AggregationBuilders.terms(ATTRIDAGG).field(ATTRID).size(100);
        attrIdAggregationBuilder.subAggregation(AggregationBuilders.terms(ATTRNAMEAGG).field(ATTRNAME).size(10));
        attrIdAggregationBuilder.subAggregation(AggregationBuilders.terms(ATTRVALUEAGG).field(ATTRVALUE).size(100));

        attrsAggregationBuilder.subAggregation(attrIdAggregationBuilder);
        nativeSearchQuery.addAggregation(attrsAggregationBuilder);

        //调用elasticsearchRestTemplate的search方法
        SearchHits<Goods> goodsSearchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Goods.class);

        //解析结果
        SearchResponseVo searchResponseVo = parseResponse(goodsSearchHits , searchParamDTO);
        return searchResponseVo;
    }

    @Override
    public void updateHotScore(Long skuId, Long hotScore) {
        Optional<Goods> goodsOptional = goodsRepository.findById(skuId);
        Goods goods = goodsOptional.get();
        goods.setHotScore(hotScore);
        goodsRepository.save(goods);
    }

    private SearchResponseVo parseResponse(SearchHits<Goods> goodsSearchHits, SearchParamDTO searchParamDTO) {

        SearchResponseVo searchResponseVo = new SearchResponseVo();
        searchResponseVo.setSearchParam(searchParamDTO);

        // 品牌的面包屑
        String trademark = searchParamDTO.getTrademark();
        if (!StringUtils.isEmpty(trademark)){
            String[] trademarkArr = trademark.split(":");
            String tmName = trademarkArr[1];
            searchResponseVo.setTrademarkParam("品牌:" + tmName);
        }

        // 平台属性面包屑
        String[] props = searchParamDTO.getProps();
        if (props != null && props.length > 0){
            //提前准备一个List集合
            List<SearchAttr> searchAttrList = new ArrayList<>();
            for (String prop : props){ // 8023:冰川蓝:颜色   ----> 平台属性的Id:平台属性的值:平台属性名称
                String[] propArr = prop.split(":");
                Long attrId = Long.parseLong(propArr[0]);
                String attrValue = propArr[1];
                String attrName = propArr[2];
                SearchAttr searchAttr = new SearchAttr(attrId, attrValue, attrName);
                searchAttrList.add(searchAttr);
            }
            searchResponseVo.setPropsParamList(searchAttrList);
        }


        // 当前页数据
        List<SearchHit<Goods>> searchHits = goodsSearchHits.getSearchHits();
        List<Goods> goodsList = searchHits.stream().map(searchHit -> {
            //元素文档数据
            Goods good = searchHit.getContent();
            Map<String, List<String>> highlightFields = searchHit.getHighlightFields();
            if (highlightFields != null && highlightFields.size() > 0){
                List<String> highlightList = highlightFields.get(TITLE);
                if (highlightList != null && highlightList.size() > 0){
                    String titleHighlight = highlightList.get(0);
                    good.setTitle(titleHighlight);
                }
            }
            return good;
        }).collect(Collectors.toList());
        searchResponseVo.setGoodsList(goodsList);

        // 排序结果
        String order = searchParamDTO.getOrder();
        SearchOrderMapVo searchOrderMapVo = new SearchOrderMapVo("1", "desc");
        if (!StringUtils.isEmpty(order) && !"null".equals(order)){
            String[] orderArr = order.split(":");
            searchOrderMapVo = new SearchOrderMapVo(orderArr[0], orderArr[1]);
        }
        searchResponseVo.setOrderMap(searchOrderMapVo);

        //分页结果参数
        searchResponseVo.setPageNo(searchParamDTO.getPageNo());
        //总记录数  总记录数 除以 每页条数  使用hutool工具的PageUtil类
        Long totalHits = goodsSearchHits.getTotalHits();
        int totalPage = PageUtil.totalPage(totalHits.intValue(), searchParamDTO.getPageSize());
        //总页数
        searchResponseVo.setTotalPages(totalPage);


        // 品牌列表
        Aggregations aggregations = goodsSearchHits.getAggregations();
        ParsedLongTerms tmIdAggTerms = aggregations.get(TMIDAGG);
        List<? extends Terms.Bucket> buckets = tmIdAggTerms.getBuckets();
        //聚合后会有多个聚合的品牌结果，所以提前创建List集合
        List<SearchTmVo> searchTmVoList = new ArrayList<>();
        for (Terms.Bucket bucket : buckets){
            //获取品牌的id 就是桶里的 key
            String tmIdStr = bucket.getKeyAsString();

            Aggregations bucketAggregations = bucket.getAggregations();
            
            //获取品牌名称
            ParsedStringTerms tmNameAggregation = bucketAggregations.get(TMNAMEAGG);
            String tmName = tmNameAggregation.getBuckets().get(0).getKeyAsString();

            //获取品牌的logoUrl
            ParsedStringTerms tmLogoUrlAggregation = bucketAggregations.get(TMLOGOURLAGG);
            String tmLogoUrl = tmLogoUrlAggregation.getBuckets().get(0).getKeyAsString();

            //封装数据
            SearchTmVo searchTmVo = new SearchTmVo();
            searchTmVo.setTmId(Long.parseLong(tmIdStr));
            searchTmVo.setTmName(tmName);
            searchTmVo.setTmLogoUrl(tmLogoUrl);
            searchTmVoList.add(searchTmVo);
        }
        searchResponseVo.setTrademarkList(searchTmVoList);

        // UrlParam
        searchResponseVo.setUrlParam(buildUrlParam(searchParamDTO));

        // 解析结果获取平台属性聚合数据
        ParsedNested attrAggregation = aggregations.get(ATTRAGG);
        Aggregations attrAggregations = attrAggregation.getAggregations();
        ParsedLongTerms attrIdAggTerms = attrAggregations.get(ATTRIDAGG);
        List<? extends Terms.Bucket> arrtIdBuckets = attrIdAggTerms.getBuckets();
        List<SearchRespAttrVo> searchResponseVoList = new ArrayList<>();
        for (Terms.Bucket attrIdBucket : arrtIdBuckets){
            //获取平台属性的id
            long attrId = Long.parseLong(attrIdBucket.getKeyAsString());

            //获取平台属性的名称
            Aggregations bucketAggregations = attrIdBucket.getAggregations();
            ParsedStringTerms attrNameAggTerms = bucketAggregations.get(ATTRNAMEAGG);
            String attrName = attrNameAggTerms.getBuckets().get(0).getKeyAsString();

            // 获取平台属性的值 (多个)
            ParsedStringTerms attrValueAggTerms = bucketAggregations.get(ATTRVALUEAGG);
            List<? extends Terms.Bucket> attrValueBuckets = attrValueAggTerms.getBuckets();
            List<String> attrValueList = new ArrayList<>();
            for (Terms.Bucket attrValueBucket : attrValueBuckets){
                String attrValue = attrValueBucket.getKeyAsString();
                attrValueList.add(attrValue);
            }

            SearchRespAttrVo searchRespAttrVo = new SearchRespAttrVo();
            searchRespAttrVo.setAttrId(attrId);
            searchRespAttrVo.setAttrName(attrName);
            searchRespAttrVo.setAttrValueList(attrValueList);
            searchResponseVoList.add(searchRespAttrVo);
        }

        searchResponseVo.setAttrsList(searchResponseVoList);

        return searchResponseVo;
    }

    private String buildUrlParam(SearchParamDTO searchParamDTO) {
        StringBuilder urlParam = new StringBuilder("list.html?");

        //1，2,3级分类
        Long category1Id = searchParamDTO.getCategory1Id();
        if (category1Id != null){
            urlParam.append("category1Id=" + category1Id);
        }

        Long category2Id = searchParamDTO.getCategory2Id();
        if (category2Id != null){
            urlParam.append("category2Id=" + category2Id);
        }

        Long category3Id = searchParamDTO.getCategory3Id();
        if (category3Id != null){
            urlParam.append("category3Id=" + category3Id);
        }

        //关键字
        String keyword = searchParamDTO.getKeyword();
        if (!StringUtils.isEmpty(keyword)){
            urlParam.append("keyword=" + keyword);
        }

        //品牌条件
        String trademark = searchParamDTO.getTrademark();
        if (!StringUtils.isEmpty(trademark)){
            urlParam.append("&trademark=" + trademark);
        }

        //属性条件
        String[] props = searchParamDTO.getProps();
        if (props != null && props.length > 0){
            for (String prop : props){
                urlParam.append("&props=" + prop);
            }
        }

        return urlParam.toString();
    }
}
